import xmlrpc.client as  xmlrpclib

from django.conf import settings
from django.core.cache import cache

import os, sys

parent_path = os.path.dirname(os.getcwd())
sys.path.append(os.path.dirname(parent_path))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cronmanger.settings")
import django

django.setup()
from supervisor_dj.models import SupervisorHost

SUPERVISOR_PASS = settings.SUPERVISOR_PASS
SUPERVISOR_USER = settings.SUPERVISOR_USER

SUPER_SUCCESS = (0, "SUCCESS")
CONN_ERR = (1, "CONN_ERR")
START_ERR = (2, "START_ERR")
STOP_ERR = (3, "STOP_ERR")
RESTART_ERR = (4, "RESTART_ERR")
GET_ONE_ERR = (5, "GET_ONE_ERR")
GET_ALL_ERR = (6, "GET_ALL_ERR")

__all__ = ['SupervisorTask2']

''' 
class SupervisorTask:
    def __init__(self):
        self.host_port = int(settings.SUPERVISOR_PORT)

    def __active_host_get(self):
        # 检查是否打开9001 supervisor
        self.host_ip_list = SupervisorHost.objects.all().values('ip')
        active_host = []
        for host_ in self.host_ip_list:
            sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sk.settimeout(0.5)
            try:
                host_ip_ = host_.get('ip', None)
                sk.connect((host_ip_, self.host_port))
                active_host.append(host_ip_)
            except Exception as e:
                logger.warning('连接主机:%s  端口:%s 超时 ' % (host_ip_, self.host_port))
                pass
                # logger.warning('连接主机:%s  端口:%s 超时 ' % (host_ip_, self.host_port))
            sk.close()
        return set(active_host)

    def __connection(self, host):
        server = xmlrpclib.Server('http://{0}:{1}@{2}:{3}/RPC2/'.format(
            settings.SUPERVISOR_USER,
            settings.SUPERVISOR_PASSWORD,
            host,
            settings.SUPERVISOR_PORT,
        ))
        return server

    def __w_2_db(self, host=None, process=None):

        if isinstance(process, list):
            # 一台服务器有多个进程

            for process_ in process:
                Supervisor.objects.create(hostip=host,
                                          hostname=host,
                                          name=process_['name'],
                                          statename=process_['statename'],
                                          description=process_['description'],
                                          start=process_['start'],
                                          stop=process_['stop'],
                                          )
        else:
            # 一台服务器上1个进程
            Supervisor.objects.create(hostip=host,
                                      hostname=host,
                                      name=process['name'],
                                      statename=process['statename'],
                                      description=process['description'],
                                      start=process['start'],
                                      stop=process['stop'],
                                      )

    def __get_allhosts_process(self):
        # 获取每台主机所有进程
        hosts_list = self.__active_host_get()
        for host_ in hosts_list:
            server = self.__connection(host_)
            try:
                all_process_res = server.supervisor.getAllProcessInfo()
            except Exception as e:
                logger.error('{} 获取进程失败密码验证'.format(host_))
            else:
                res_ = []
                res_.append(host_)
                res_.append(all_process_res)
                yield res_
                # 返回的进程 列表或者
                #  [host1, [ {process1} ]

    def get_all_process(self, host=None, process=None):
        # 判断是单台 还是多台
        if not host and not process:
            # 如果不传入 主机和进程信息 则默认刷新列表
            Supervisor.objects.all().delete()
            for tmp in self.__get_allhosts_process():
                host_ = tmp[0]
                process_ = tmp[1]
                self.__w_2_db(host_, process_)
        else:
            Supervisor.objects.filter(hostip=host).delete()
            self.__w_2_db(host, process)

    def get_single_host_process(self, host):
        # 获取单台主机的进程列表
        server = self.__connection(host)
        try:
            all_process_res = server.supervisor.getAllProcessInfo()

        except Exception as e:
            logger.error('{}获取获取单台主机进程失败 验证失败'.format(host))
            return e.args
        else:
            self.get_all_process(host, all_process_res)
            return True

    def start(self, host, process_name):
        server = self.__connection(host)
        try:
            res = server.supervisor.startProcess(process_name)
        except Exception as e:
            emsg = "启动{} {}进程失败{}".format(host, process_name, e.args)
            logging.error(emsg)
            res = emsg
        if res == True:
            self.get_single_host_process(host)
        return res

    def stop(self, host, process_name):
        server = self.__connection(host)
        try:
            res = server.supervisor.stopProcess(process_name)
        except Exception as e:
            emsg = "停止{} {}进程失败{}".format(host, process_name, e.args)
            logging.error(emsg)
            res = emsg
        if res == True:
            res = self.get_single_host_process(host)
        return res

    def restat(self, host, process_name):
        server = self.__connection(host)
        p_statename = server.supervisor.getProcessInfo(process_name)["statename"]
        if p_statename == 'RUNNING':
            res = self.stop(host, process_name)
        res = self.start(host, process_name)
        return res
'''


class SupervisorTask2:

    def __init__(self, username=SUPERVISOR_USER, password=SUPERVISOR_PASS, host=None, port=None):
        """
        初始化连接信息
        :param username:
        :param password:
        :param host:
        :param port:
        """

        self.username = username
        self.password = password
        self.host = host
        self.port = port
        self.status = SUPER_SUCCESS
        self.supervisor_obj = self.get_connecti(self.host, self.port, self.username, self.password).supervisor

    def get_connecti(self, host=None, port=None, username=None, password=None):
        """
        初始化连接信息
        :param host:
        :param port:
        :param username:
        :param password:
        :return:  连接对象     server = xmlrpclib.Server('http://zrd:sh123!@192.168.1.60:9001/RPC2/')
        """

        # 无密码和账号
        connection_info_no_pass = f'http://{host}:{port}/RPC2/'
        if username and password:
            # 有密码和账号
            connection_info = f'http://{username}:{password}@{host}:{port}/RPC2/'
            server = xmlrpclib.Server(connection_info)
            return server
        return xmlrpclib.Server(connection_info_no_pass)

    def start(self, p_name=None, host=None):
        """
        启动被管理进程
        :param p_name:    接收进程名
        :return: 返回执行结果
        """
        self.host = host
        try:
            status = self.get_process_status(process_name=p_name)
            if status == 'RUNNING':
                return '程序已经在运行'
            return self.supervisor_obj.startProcess(p_name)
        except xmlrpclib.Fault  as e:
            self.status = START_ERR
            return e.faultString
        except Exception as e:
            self.status = START_ERR
            return e.args

    def stop(self, p_name=None, host=None):
        """
        停止被管理进程
        :param p_name:
        :return:   返回执行结果
        """
        self.host = host
        try:
            status = self.get_process_status(process_name=p_name)
            if status == 'STOPPED':
                return '程序已停止'
            return self.supervisor_obj.stopProcess(p_name)
        except xmlrpclib.Fault  as e:
            self.status = STOP_ERR
            return e.faultString
        except Exception as e:
            self.status = STOP_ERR
            return e.args

    def restart(self, p_name=None, host=None):
        """
        重启被管理进程
        :param p_name:
        :return:
        """
        self.host = host
        status = self.get_process_status(process_name=p_name)
        if status == 'RUNNING':
            stop_obj = self.stop(p_name)
            if self.status[0] != 0:
                return stop_obj
        return self.start(p_name)

    def get_a_process_info(self, p_name=None):
        """ 获取被管理进程详情"""
        try:
            return self.supervisor_obj.getProcessInfo(p_name)
        except xmlrpclib.Fault as e:
            self.status = GET_ONE_ERR
            return e.faultString
        except Exception as e:
            self.status = GET_ONE_ERR
            return e.args

    def get_all_process_info(self):
        """
        获取所有被管理进程信息
        :return:
        """
        try:
            return self.supervisor_obj.getAllProcessInfo()
        except xmlrpclib.Fault as e:
            self.status = GET_ALL_ERR
            return e.faultString
        except Exception as e:
            self.status = GET_ALL_ERR
            return e.args

    def write_to_cache_list_type(self, host=None, process_list=None, ):
        """  TODO 使用后台队列写入
        格式化进程消息2

        :param host:
        :param process_list:     get_all_process_info函数返回的列表数据类型[{进程x信息},{进程y信息},.....]
        :return:
        """
        # 进程名
        w_key = "supervisor${host}${p_name}"
        if isinstance(process_list, list):
            for process in process_list:
                p_name = process['name']

                new_process_name = w_key.format(host=host, p_name=p_name)
                write_process_to_redis(host=host, key=new_process_name, value=process)

    def write_to_cache_one_process(self, host=None, process_info=None):
        """       TODO 使用后台队列写入
        格式化进程消息2
        :param host:
        :param process:        get_a_process_info函数返回一个进程类型   {进程信息}
        :return:
        """
        p_name = process_info.get('name') if isinstance(process_info, dict) else None
        w_key = "supervisor${host}${p_name}".format(host=host, p_name=p_name)
        write_process_to_redis(host=None, key=w_key, value=process_info)

    def refreshall(self):
        """
        刷新所有被管理进程信息，从数据库中获取主机ip，遍历刷新到缓存(redis)中
        :return:
        """
        host_list = SupervisorHost.objects.values_list('ip', 'port')
        for ip, port in host_list:
            process_list = SupervisorTask2(host=ip, port=port).get_all_process_info()
            self.write_to_cache_list_type(host=ip, process_list=process_list)

    def get_process_status(self, process_name):
        """

        :param process_name:
        :return:       RUNNING or STOPPED or UNKNOWN
        """
        process_info = self.get_a_process_info(process_name)
        p_status = process_info.get("statename")
        if p_status == "RUNNING":
            return "RUNNING"
        if p_status == "STOPPED":
            return "STOPPED"
        return "UNKNOWN"

    def get_a_prcoess_info_from_redis(self, processs_name, host=None):
        """

        :param processs_name:
        :return:
        """
        host = host if host else self.host
        w_key = "supervisor${host}${p_name}".format(host=host, p_name=processs_name)
        return cache.get(w_key)

    @staticmethod
    def get_all_process_info_from_redis():
        """

        :return:返回所有的    superviso进程信息
        """
        return cache.iter_keys("supervisor*")

    def get_a_host_process(self, host):
        w_key = "supervisor${host}*".format(host=host)
        return cache.iter_keys(w_key)

    @classmethod
    def superhostlist(cls):
        supervisor_hostlist = cache.get('superhostlist', [])
        return supervisor_hostlist


def write_process_to_redis(host, key, value):
    cache.set(key, value, timeout=None)

    supervisor_hostlist = cache.get('superhostlist', [])
    supervisor_hostlist.append(host)
    supervisor_hostlist = list(set(supervisor_hostlist))
    cache.set('superhostlist', supervisor_hostlist, timeout=None)


"""
只有主机ip和密码

start

stop

restart

连接前检查端口连通性？  （取消，直接操作，抓取异常）

[{
'description': 'pid 8422, uptime 1 day, 18:49:59',
'pid': 8422, 
'stderr_logfile': '', 
'stop': 1521880185,
'logfile': '/tmp/python_amon_gunicorn.log',
'exitstatus': 0,
'spawnerr': '',
'now': 1522036704,
'group': 'python_amon_gunicorn',
'name': 'python_amon_gunicorn', 
'statename': 'RUNNING',
'start': 1521882505, 
'state': 20, 'stdout_logfile': '/tmp/python_amon_gunicorn.log'
},

{'description': 'pid 32509, uptime 2 days, 16:40:30', 'pid': 32509, 'stderr_logfile': '', 'stop': 1521803868, 'logfile': '/tmp/zrd_mongod.log', 'exitstatus': 0, 'spawnerr': '', 'now': 1522036704, 'group': 'zrd_mongod', 'name': 'zrd_mongod', 'statename': 'RUNNING', 'start': 1521803874, 'state': 20, 'stdout_logfile': '/tmp/zrd_mongod.log'}]

"""

if __name__ == '__main__':

    user_name = "zrd"
    password = 'sh123!'
    host = '192.168.1.60'
    port = 9001

    s = SupervisorTask2(username=user_name, password=password, host=host, port=port)

    test_process_name = "python_amon_gunicorn"
    # start
    start = s.start(test_process_name)
    print(f"测试启动进程 start: {test_process_name}\n", start)
    print("status: ", s.status)
    print('=============\n')

    # stop
    stop = s.stop(test_process_name)
    print(f"测试停止进程 stop: {test_process_name}\n", stop)
    print("status: ", s.status)
    print('=============\n')

    # restart
    restart = s.restart(test_process_name)
    print(f"测试重启进程 restart: {test_process_name}\n", restart)
    print("restart:", s.status)
    print('=============\n')

    # info  get one process
    one_process_info = s.get_a_process_info(test_process_name)
    print(f"测试获取一个进程信息 one_process_info: {test_process_name} \n", one_process_info)
    print("status: ", s.status)

    # info get all processes
    all_process_info = s.get_all_process_info()
    print(f"测试获取所有进程信息  info get all processes {test_process_name}\n", all_process_info)
    print("status: ", s.status)

    # write one process info to redis
    host = s.host
    print("\n测试将一个进程信息写入redis:")
    s.write_to_cache_one_process(host=host, process_info=one_process_info)

    # write all process info to redis
    host = s.host
    print("\n测试一个进程列表信息写入redis:")
    s.write_to_cache_list_type(host=host, process_list=all_process_info)

    # get one process from redis
    print("\n测试从redis读取一个进程:")
    res = s.get_a_prcoess_info_from_redis(test_process_name)
    print("res", res)

    # info get     all process from redis
    print("\n测试从redis读取所有进程:")
    for i in s.get_all_process_info_from_redis():
        print(i, cache.get(i))

    # get a host all processes
    print("\n指定ip测试从redis读取该ip所有进程:")
    for i in s.get_a_host_process(host=host):
        print(i, ": ", cache.get(i))

    # refreshall 刷新所有(从数据库中刷新)
    s.refreshall()
